<!DOCTYPE html>
<html>
    <head>
        <title>Ruler - Metric & Imperic</title>

        <style type="text/css">
            body{margin:0;}
        </style>

        <script type="text/javascript">



window.onload = function() {
    //doSpiral()

    var properties = {stroke: '#ddd', strokeWidth: .2, rings: 5, spiralB: 2.4};

    var svg = document.getElementById("ruler");

    drawSpiral(svg, properties, 0);
    drawSpiral(svg, properties, 5);
    drawSpiral(svg, properties, -5);

    //print mm
    drawMMTicks(svg, properties);

    //print inch ticks

}



/*
 * Create an Archimedean spiral using minimal quadratic Bezier path.
 * Omit the first inner ring, i.e. f(theta) = a + b * theta  :  [theta >= 2 * Math.PI]
 */
function drawSpiral(svg, props, a) {
    var spiral = document.createElementNS("http://www.w3.org/2000/svg", "path");

    var thetaStep = Math.PI / 4;  //this is good value, i.e. keep.
    var b = props.spiralB;
    var d = "M" + (a + 2 * Math.PI * b) + " 0 Q ";  //start spiral after 1st round

    spiral.setAttribute("fill", "none");
    spiral.setAttribute("stroke", props.stroke);
    spiral.setAttribute("stroke-width", props.strokeWidth);

    for (var theta = Math.PI * 2 + thetaStep, step = 9; theta <= (props.rings + 1) * 2 * Math.PI; theta = ++step * thetaStep) {
            var r = a + b * theta;             //radius at point x1, y1
            var x1 = r * Math.cos(theta);  //next endpoint x
            var y1 = r * Math.sin(theta);  //next endpoint y

            //Slope of spiral at point (x1,y1), see http://tutorial.math.lamar.edu/Classes/CalcII/PolarTangents.aspx
            var m1 = (b * Math.sin(theta) + a * Math.cos(theta) + b * theta * Math.cos(theta)) / (b * Math.cos(theta) - a * Math.sin(theta) - b * theta * Math.sin(theta));
            //Slope of line from origin through control point
            var m2 = Math.tan(theta - thetaStep / 2);

            var x2 = (-m1 * x1 + y1) / (m2 - m1);  //control point x
            var y2 = m2 * x2;                      //control point y

            d += " " + x2 + " " + y2 + " " + x1 + " " + y1 + " ";  //(x1 y1 x y)+   ->   quadratic polybezier   http://www.w3.org/TR/SVGTiny12/paths.html
        }

    spiral.setAttribute("d", d);
    svg.appendChild(spiral);
    return spiral;
}



function drawTick(svg, b, theta, r1, r2) {
    //mm ticks in 1mm increments
    //var r = b * theta;         //radius at point x1, y1
    var x1 = r1 * Math.cos(theta);  //next endpoint x
    var y1 = r1 * Math.sin(theta);  //next endpoint y
    var dash = document.createElementNS("http://www.w3.org/2000/svg", "line");

    var x2 = r2 * Math.cos(theta);  //next endpoint x
    var y2 = r2 * Math.sin(theta);  //next endpoint y
    dash.setAttribute("stroke-width", 0.1);
    dash.setAttribute("fill", "none");
    dash.setAttribute("stroke", "#000");

    dash.setAttribute("x1",x1);
    dash.setAttribute("y1",y1);
    dash.setAttribute("x2",x2);
    dash.setAttribute("y2",y2);
    svg.appendChild(dash);
}



function drawText(svg, text, theta, r1) {
    var textX = r1 * Math.cos(theta);
    var textY = r1 * Math.sin(theta);
    var digit = document.createElementNS("http://www.w3.org/2000/svg", "text");
    var g = document.createElementNS("http://www.w3.org/2000/svg", "g");
    g.setAttribute("transform", "rotate(" + (90 + theta * 180 / Math.PI) + " " + textX + " " + textY + ")");
    digit.setAttribute("fill", "#000");
    digit.setAttribute("font-size", "0.75mm");
    digit.setAttribute("x", textX);
    digit.setAttribute("y", textY);
    digit.setAttribute("text-anchor", 'left');
    digit.setAttribute("font-family", 'Gill Sans MT,Arial');

    digit.textContent = text;
    g.appendChild(digit);
    svg.appendChild(g);
}



function drawMMTicks(svg, props) {
    var mmPunit = 1;  //mm / unit
    var inPunit = mmPunit / 25.4;  //in / unit
    var last = -1;
    var temp;
    var b = props.spiralB;
    var angle = -1;
    var twoPI = Math.PI * 2;
    var lastInch = -1;
    var inchInt = 1/16;
    var mmInt = 1;
    var numMMs = -1;
    var numSixteenths = -1;
    var startLength = getSpiralLength(Math.PI * 2, b);  //since we are starting at 2PI, subtract that from lengths
    var dashLength;

    for (var theta = twoPI, radius = b * theta; theta <= (props.rings + 1) * 2 * Math.PI; theta += .000001, radius = b * theta) {
        temp = getSpiralLength(theta, props.spiralB) - startLength;

        if (temp * mmPunit >= last + mmInt) {
            ++numMMs;
            last = temp * mmPunit;
            switch (numMMs % 10) {
                case 0: dashLength = 4; break;
                case 5: dashLength = 1.5; break;
                default: dashLength = .5;
            }

            drawTick(svg, b, theta, radius, radius - dashLength);

            //mm text digit
            if (numMMs % 10 === 0) {
                drawText(svg, numMMs, theta, radius - 4);
            }
        }

        if (temp * inPunit >= lastInch + inchInt) {
            ++numSixteenths;
            lastInch = temp * inPunit;
            switch (numSixteenths % 16) {
                case 0: dashLength = 4;break;
                case 8: dashLength = 3;break;
                case 4:
                case 12: dashLength = 2;break;
                case 2:
                case 6:
                case 10:
                case 14: dashLength = 1.25;break;
                default : dashLength = 0.75;
            }
            drawTick(svg, b, theta,radius, radius + dashLength);
            if (numSixteenths % 16 === 0) {
                drawText(svg, numSixteenths / 16, theta, radius + 2);
            }
        }

    }
}



function getSpiralLength(theta, b) {
    //http://mathworld.wolfram.com/ArchimedesSpiral.html
    return (1/2) * b * ((theta * Math.sqrt(1 + Math.pow(theta, 2)) + (Math.log(Math.sqrt(1 + Math.pow(theta, 2))))));
}



        </script>
    </head>
    <body>
        <!-- assume 8" square to be printed on 8.5" x 11" with 0.25" margins -->
        <svg style="display:none;" width="203.2mm" height="203.2mm" viewBox="0 0 203.2 203.2" xmlns:svg="http://www.w3.org/2000/svg" xmlns="http://www.w3.org/2000/svg" version="1.0">
            <rect x="0" y="0" width="203.2" height="203.2" stroke="#eee" fill="none" stroke-width="1" />
        </svg>
        <!-- assume 8" square to be printed on 8.5" x 11" with 0.25" margins -->
        <svg id="ruler" width="203.2mm" height="203.2mm" viewBox="-101.6 -101.6 203.2 203.2" xmlns:svg="http://www.w3.org/2000/svg" xmlns="http://www.w3.org/2000/svg" version="1.0">
            <rect x="-101.6" y="-101.6" width="203.2" height="203.2" fill="none" />
        </svg>
    </body>
</html>